package jdklearning.concurrent.thread;

import java.lang.management.ManagementFactory;

import java.util.concurrent.locks.LockSupport;

/**
 * @author shenenlu 2021年02月19日 下午12:40:46
 * 这里为了方便得到java进程id，直接使用pid()函数输出。为了方便，我们把观察线程固定为”main”，因为JVM还有其他线程都会存在输出中，
 * 我们可以通过关键字”main”找到我们要观察的线程。命令jstack -l [pid]。
 *
 *
 * yield：让出时间片，不会释放锁
 *
 * sleep：线程进入睡眠状态，不会释放锁
 *
 * wait：调动方法之前，必须要持有锁。调用了wait()方法以后，锁就会被释放，进入锁的等待队列，方法返回后重新拿到锁
 *
 * notify：调动方法之前，必须要持有锁，调用notify()方法本身不会释放锁的。而是通知等待队列中的某一个线程，同步代码块执行完毕后才会释放锁
 *
 * notifyAll:同notify，有一点不同在于，notifyAll会发出n个信号（n=等待线程数），而notify只会发出一个信号，通常情况下，尽量选择notifyAll
 * 原文链接：https://blog.csdn.net/a1173537204/article/details/89211639
 */
public class ThreadStatusLearning {
    public static void main(String[] args) {
        System.out.println(pid());
//        runnable();     // 1
//     blocked();      // 2
//     waiting();      // 3
//     timedWaiting(); // 4

        isAliveTest();
    }

    public static String pid() {
        String name = ManagementFactory.getRuntimeMXBean().getName();
        return name.split("@")[0];
    }


    /**
     * 没什么好解释的，死循环即可。
     */
    public static void runnable() {
        long i = 0;
        while (true) {
            i++;
        }
    }


    /**
     * 主线程sleep，先让另外一个线程拿到lock，并长期持有lock（sleep会持有锁，wait不会）。此时主线程会BLOCK住等待lock被释放，
     * 此时jstack的输出可以看到main线程状态是BLOCKED。这里要注意的是只有synchronized这种方式的锁（monitor锁）才会让线程出现BLOCKED状态，等待ReentrantLock则不会。
     */
    public static void blocked() {
        final Object lock = new Object();
        Thread t = new Thread(() -> {
            synchronized (lock) {
                System.out.println("i got lock, but don't release");
                try {
                    Thread.sleep(1000L * 1000);
                } catch (InterruptedException e) {
                }
            }
        });
        t.setName(ThreadStatusLearning.class.getSimpleName() + "-locked");
        t.start();

        try { Thread.sleep(100); } catch (InterruptedException e) {}

        synchronized (lock) {
            try {
                Thread.sleep(30 * 1000);
            } catch (InterruptedException e) {
            }
        }
    }


    /**
     * 用Lock.tryLock(timeout, timeUnit)，这种方式也会看到TIMED_WAITING状态，这个状态说明线程当前的等待一定是可超时的。
     */
    public static void timedWaiting() {
        final Object lock = new Object();
        synchronized (lock) {
            try {
                lock.wait(30 * 1000);
            } catch (InterruptedException e) {
            }
        }
//        LockSupport.parkNanos(500000000000000000L);
    }



    /**
     * 无超时的等待，必须等待lock.notify()或lock.notifyAll()或接收到interrupt信号才能退出等待状态。
     * 同理，ReentrantLock.lock()的无参方法调用，也会使线程状态变成WAITING。
     */
    public static void waiting() {
//        final Object lock = new Object();
//        synchronized (lock) {
//            try {
//                lock.wait();
//            } catch (InterruptedException e) {
//            }
//        }
        LockSupport.park();
    }



    public static void isAliveTest(){
        Thread t = new Thread("t1"){
            @Override
            public void run() {
                try {
                    sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        t.start();
        while (true){
            System.out.println("t1.isAlive: " + t.isAlive());
        }
    }

}
